<template>
  <div class="chatContain" ref="chatContainer">

    <ChatBox :position="item.position" :message="item.msg" :key="item.index" v-for="item in chatContext" />
    <div id="mao" ref="maoPoint"></div>
  </div>
  <!--  <div>{{ isMaoPointVisible }}</div>-->
</template>


<script setup>
import ChatBox from "./ChatBox.vue";
import { watch, reactive, ref, defineEmits } from "vue";
import { ElMessage } from "element-plus";
import { markdownToHtml } from '../../utils/highLightCode'
import { getTokens } from "../../api/api";
import pinia from "../../store";//引入pinia
import { pageStore } from "../../store/ChatPage";
import { storeToRefs } from "pinia";
import { EventSourcePolyfill } from "event-source-polyfill";
import Cookies from "js-cookie";
import { useIntersectionObserver } from "@vueuse/core"; //引用监听页面滚动变换

//引入chatpage页面的状态管理
const chatpage = pageStore(pinia);
const { mode, question, isInterrupt, isThinking } = storeToRefs(chatpage);

//通过ref获取锚点
const maoPoint = ref(null);
const isMaoPointVisible = ref(false);
const chatContainer = ref(null)//获取chatContain
useIntersectionObserver(maoPoint, ([{ isIntersecting }]) => {
  isMaoPointVisible.value = isIntersecting;
}, {
  root: chatContainer,
  rootMargin: "70px",
})//响应式监听锚点是否在可视范围内


//设置emits控制ChatPage输入框聚焦
const emits = defineEmits(["focus"]);
// 响应式数组 聊天内容
const chatContext = reactive([
  {
    position: "1",
    msg: "Hello! Im BitGPT",
  },
]);

//暂时储存流式传输的内容
const allContent = ref("");

//监听props.Context的变化
watch(
  () => question.value,
  (val) => {
    if (val != "") {
      handleSendmsg(val);
    }
  }
);

//一个异步方法渲染chatContext，传入参数为message，点击发送按钮时触发
const handleSendmsg = async (message) => {
  //添加用户输入的对话框
  await addContext("2", message);
  focusMao();
  /* 流式传输 */
  await waitAnswerComplete(message);
  await getTokens()
  await resetContext();
  emits("focus");
  // focusMao();
};

//流式传输等待回答完成
const waitAnswerComplete = (question) => {
  return new Promise(async (resolve) => {
    //先添加空对话框
    await addContext("1", "Thinking...");
    focusMao()

    let es = null;
    //根据不同的模式发送不同的请求
    if (mode.value === 'Chat') {
      es = new EventSourcePolyfill(`${import.meta.env.PROD ? import.meta.env.VITE_PROD_URL : "/api"}/chat/question?question=${question}`, {
        withCredentials: true
      });
    } else if (mode.value === 'ChatGPT4') {
      es = new EventSourcePolyfill(`${import.meta.env.PROD ? import.meta.env.VITE_PROD_URL : "/api"}/chat/question4?question=${question}`, {
        withCredentials: true
      });
    }


    //监听eventsource的message事件
    es.onmessage = async (event) => {
      if (chatContext[chatContext.length - 1].msg === "Thinking...") {
        writeMessageToBitgpt(""); //清空'Thinking...'
      }
      //回答结束则关闭eventsource
      if (event.data === "[DONE]") {
        console.log("done");
        isThinking.value = false;
        es.close();
        resolve(1);
        return 0;
      }
      //今日使用超出限制
      if (event.data === "[UNABLE TO ASK]") {
        ElMessage.error("今日使用超出限制");
        writeMessageToBitgpt("今日使用次数已达上限");
        isThinking.value = false;
        es.close();
        resolve(1);
        return 0;
      }
      //检测是否手动中断
      else if (isInterrupt.value === true) {
        resolve(1);
        isInterrupt.value = false;
        es.close();
        return 0;
      }
      //正常拿到数据
      else if (isInterrupt.value !== true) {
        try {
          //转换拿到的数据
          // if (event.data != "") {
          const data = JSON.parse(event.data);
          const { content = "" } = data.choices[0].delta;
          allContent.value += content;
          // console.log(allContent.value);
          //将回答暂存，再将markdown拿去转换成html
          // console.log(event.data);
          // allContent.value += event.data;
          // console.log(event.data.includes('\n'));

          writeMessageToBitgpt(allContent.value);
          // }
        } catch (error) {
          console.log(event);
          console.log(error);
          allContent.value = "错误，请稍后尝试";
          writeMessageToBitgpt(allContent.value);
          isThinking.value = false;
          es.close();
          resolve(1);
          return 0;
        }
      }
      //贴底的情况下，聚焦底部
      if (isMaoPointVisible.value === true) focusMao();
    };

    //监听eventsource的error事件
    es.onerror = (err) => {
      console.log(err);
      ElMessage.error("服务器错误，请稍后尝试");
      writeMessageToBitgpt("服务器错误，请稍后尝试");
      isThinking.value = false;
      resolve(1);
      return es.close();
    };

  });
};
//将markdown转换成html后写入chatcontext
const writeMessageToBitgpt = (message) => {
  markdownToHtml(message).then((res) => {
    chatContext[chatContext.length - 1].msg = res;
  });
};
//写一个异步方法向chatcontext里添加数据，传入参数为position和msg
const addContext = (position, msg) => {
  return new Promise((resolve) => {
    chatContext.push({
      position: position,
      msg: msg,
    });
    resolve();
  });
};
//重置存有的聊天内容
const resetContext = () => {
  return new Promise((resolve) => {
    allContent.value = "";
    question.value = "";
    resolve();
  });
};
//聚焦底部
const focusMao = () => {
  const mao = document.getElementById("mao");
  mao.scrollIntoView();
};
</script>

<style scope>
.chatContain {
  margin-right: 5%;
  overflow: auto;
  width: 90%;
  height: 100%;
  background-color: black;
  border-radius: 20px;
  padding: 10px;
  border: 10px solid black;
  box-shadow: 1px 1px 10px 1px black;
}

#mao {
  height: 0px;
  width: 0px;
}

@media screen and (max-width: 1400px) {
  .chatContain {
    margin-right: 0;
    width: 97%;
  }
}
</style>